import '../logger.dart';
import 'summary.dart';

typedef Calculator = dynamic Function();
typedef AvgTimes = Future<Summary> Function(int times);

AvgTimes avg(Calculator calculator) {
  return (int times) async {
    int durationInSuccess = 0;
    final costs = <int>[];
    final exceptions = List<Exception>();
    int successTimes = 0;
    for (int i = 0; i < times; i += 1) {
      final cst = DateTime.now();
      try {
        await calculator();
        successTimes += 1;
      } catch (ex) {
        exceptions.add(ex);
        Logger.e(msg: 'avg calculator execute failure...$ex');
        continue;
      } finally {
        durationInSuccess += DateTime.now().difference(cst).inMilliseconds;
      }
      costs.add(DateTime.now().difference(cst).inMilliseconds);
    }
    final avg = successTimes > 0 ? durationInSuccess / successTimes : -1;
    return Summary(
        sampleTimes: times,
        successTimes: successTimes,
        avg: avg.floor(),
        P90: quantileLessThan(costs, 0.9),
        P50: quantileLessThan(costs, 0.5),
        exceptions: exceptions);
  };
}

int quantileMoreThan(final Iterable<int> numbers, double percent) {
  if (numbers.length == 0) {
    return -1;
  }
  return quantileLessThan(numbers, 1 - percent);
}

int quantileLessThan(final Iterable<int> numbers, double percent) {
  if (numbers.length == 0) {
    return -1;
  }
  final data = List.of(numbers);
  data.sort((p, n) => p - n);
  final position = (numbers.length * percent).floor();
  return data[position];
}
